Backup cron jobs#307
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a Linux script intended to support daily PostgreSQL backups for the Dockerized TEKDB deployment by dumping the db container’s database to a local backups/ directory.
Changes:
- Introduces
scripts/Linux/db-backups-cron.shto load prod env vars and generate a timestampedpg_dumpoutput file. - Creates a local backup directory (
backups/postgres) and writes SQL dumps there.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| mkdir -p "${BACKUP_DIR}" | ||
|
|
||
| 0 9 * * * docker exec -i "${CONTAINER_NAME}" pg_dump -U "${DB_USER}" "${DB_NAME}" > "${FINAL_BACKUP_FILE}" |
There was a problem hiding this comment.
This belongs in the cron file - either script writing this line to the cron file or document a manual process for adding it - since we don't know when is best for people to run or what timezone they are running on their server.
Reading Copilot's response, I see it's confused by and keying in on some possible lack of clarity around where this script is used and what role it fills. Is it:
- A 1-off script run during installation intended to set up a cron job on the server so backups persist going forward? (I read it as this)
- The script to be run by a cron job (Copilot reads it as this), or
- The text for the cron job itself (no one thinks it's this, but that is where this final line would belong as written
I'm happy to answer questions or recommend approaches.
There was a problem hiding this comment.
Great point. I've refactored the script to just write the output of pg_dump to a sql file.
Would it make sense to have as part of the sys admin documentation for installing an instance with Docker to have instructions for setting up a cron job for regular backups? Or do you think it would be preferable to have this further scripted/automated?
The docs could include something like the following:
SQL Backups
- Determine how often you'd like to run a SQL backup
* * * * * /path/to/command │ │ │ │ │ │ │ │ │ └─ Day of the week (0 - 6) (Sunday to Saturday) │ │ │ └──── Month (1 - 12) │ │ └─────── Day of the month (1 - 31) │ └────────── Hour (0 - 23) └───────────── Minute (0 - 59)
- To setup a Cron Job for regular SQL dumps run
sudo crontab -e:<your cadence> /tekdb/db-dump.sh
| @@ -0,0 +1,24 @@ | |||
| #!/bin/bash | |||
| set -e | |||
| #!/bin/bash | ||
| set -e | ||
|
|
||
| ENV_FILE=".env.prod" |
| DB_USER=${SQL_USER} | ||
| DB_NAME=${SQL_DATABASE} |
| CONTAINER_NAME=db | ||
| DB_USER=${SQL_USER} | ||
| DB_NAME=${SQL_DATABASE} | ||
| BACKUP_DIR="../../backups/postgres" |
| mkdir -p "${BACKUP_DIR}" | ||
|
|
There was a problem hiding this comment.
Not bad advice, but if someone has access to the server they have easier ways of accessing this sensitive info. Protecting this dir at this level is a little... "decorative".
| DATE=$(date +%Y-%m-%d_%H%M%S) | ||
| FINAL_BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_${DATE}.sql" | ||
|
|
There was a problem hiding this comment.
Copilot suggests setting up a retention policy (i.e. a single "delete files older than x that match name pattern y" line) -- but there's a more efficient/lazier option:
- The purpose of this script is to dump a static file that will be collected by regular (daily?) file system backups
- Iff this is part of a larger, recurring, and time-stamped system that runs in a similar cadence to this cron job:
- There is no need to append the datetime to make the filename unique - just overwrite it
- You can use the backup system to access prior states
- You will have smaller backups
- You will have a simpler backup logic
The lazy path makes several assumptions that should be well-reinforced in the docs (including possibly some hairy work to understand the difference between the time zone of the external backup system vs what timezone the server thinks it lives in), though the 'clean up after yourself' script isn't too difficult either. Not doing either, however, is not a good idea.
There was a problem hiding this comment.
Heard! Sounds like your proposal is to have these .sql files have the same file name and be overwritten on a regular cadence (daily). Sys admins will then have a file system backup that will take these sql files, and create a backup system.
Do we feel like it is a safe assumption that sys admins will have this in place?
There was a problem hiding this comment.
- Assumptions are never safe, so "no"
- However, the time-stamped dumpfile is only better by the number of days of retention you would otherwise implement, after which, if the sysadmin doesn't have a filesystem backup in place:
- They won't be able to restore prior to the retention window
- They run the risk of losing the host FS, where they'd be just as screwed as they would under either system (or no backup system whatsoever!)
So I guess the answer is: Make sure having a sysadmin set up file-system backups is a early and absolutely required step of setup/migration (in all documentation and any on-prem deployment/migration playbook we write). After which there is no real difference between these approaches, so long as one is implemented.
There was a problem hiding this comment.
A (admittedly feeble) prior attempt was made by including this in the 'Requirements' document.
We can probably do better, but so long as this is in place, perhaps you are right - we can assume this is documented (it's their responsibility) and we can assume file-system backups are in place. Sorry to be flip-flopping.
There was a problem hiding this comment.
Okay, I think it makes sense to have the onus of backups be on the Sys Admins, and we can make that as easy as we can while the burden rests on them. We will have documentation and scripts to make that as simple as we can, while leaving room for configuration, such as the cadence and timing.
rhodges
left a comment
There was a problem hiding this comment.
The last line doesn't do what you think it does. Without changes this will not accomplish to goal of getting the server to dump backup files.
I think there also needs to be some more thought put into syncing backup timelines and anticipating confusion around time zones.
| ENV_FILE=".env.prod" | ||
|
|
||
| if [ -f "$ENV_FILE" ]; then | ||
| set -a |
| DATE=$(date +%Y-%m-%d_%H%M%S) | ||
| FINAL_BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_${DATE}.sql" | ||
|
|
There was a problem hiding this comment.
Copilot suggests setting up a retention policy (i.e. a single "delete files older than x that match name pattern y" line) -- but there's a more efficient/lazier option:
- The purpose of this script is to dump a static file that will be collected by regular (daily?) file system backups
- Iff this is part of a larger, recurring, and time-stamped system that runs in a similar cadence to this cron job:
- There is no need to append the datetime to make the filename unique - just overwrite it
- You can use the backup system to access prior states
- You will have smaller backups
- You will have a simpler backup logic
The lazy path makes several assumptions that should be well-reinforced in the docs (including possibly some hairy work to understand the difference between the time zone of the external backup system vs what timezone the server thinks it lives in), though the 'clean up after yourself' script isn't too difficult either. Not doing either, however, is not a good idea.
| mkdir -p "${BACKUP_DIR}" | ||
|
|
There was a problem hiding this comment.
Not bad advice, but if someone has access to the server they have easier ways of accessing this sensitive info. Protecting this dir at this level is a little... "decorative".
|
|
||
| mkdir -p "${BACKUP_DIR}" | ||
|
|
||
| 0 9 * * * docker exec -i "${CONTAINER_NAME}" pg_dump -U "${DB_USER}" "${DB_NAME}" > "${FINAL_BACKUP_FILE}" |
There was a problem hiding this comment.
This belongs in the cron file - either script writing this line to the cron file or document a manual process for adding it - since we don't know when is best for people to run or what timezone they are running on their server.
Reading Copilot's response, I see it's confused by and keying in on some possible lack of clarity around where this script is used and what role it fills. Is it:
- A 1-off script run during installation intended to set up a cron job on the server so backups persist going forward? (I read it as this)
- The script to be run by a cron job (Copilot reads it as this), or
- The text for the cron job itself (no one thinks it's this, but that is where this final line would belong as written
I'm happy to answer questions or recommend approaches.
fail fast if no .env.prod file
dont use PWD in crontab
|
|
||
| echo "Pulling the latest Docker image..." | ||
| docker pull ghcr.io/ecotrust/tekdb/web:latest | ||
| sudo docker pull ghcr.io/ecotrust/tekdb/web:latest |
There was a problem hiding this comment.
needed to change to sudo to prevent error of permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
|
@rhodges I've successfully gone through the install instructions and setting up a cronjob on an EC2 instance. I think this work is good to go. |
rhodges
left a comment
There was a problem hiding this comment.
Tested: this coupled with adding sudo before running the install script in the docs (done) results in quick and easy deployment with clear printed instructions for configuring crontab files (with appropriate permissions).
asana task
Adds a script to start a cron job to run at 9am daily to dump the database to a local sql file in a directory named "backups".
I was thinking that in the docs we can add a step for starting this cron job with this script, as an optional step in the install process. An alternate approach could be to have the cron job instantiated as part of the install script. I'm open to peoples opinions on which is the better approach.